package com.lenovo.redission.redission.service.impl;

import com.lenovo.redission.redission.config.lock.DistributedLock;
import com.lenovo.redission.redission.lock.IDistributedLock;
import com.lenovo.redission.redission.model.RedisSerializableModel;
import com.lenovo.redission.redission.service.RedisTestService;
import jodd.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.log4j.Log4j2;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.util.concurrent.*;

@Service
@Log4j2
public class RedisTestServiceImpl implements RedisTestService {

    @Autowired(required = false)
    private IDistributedLock redisLock;

    /**
     * 高可用 大于一半加锁成功才成功
     */
    public void redissonRedLock() {
        //多个redis服务器产生的锁
        RLock[] locks = null;
        RedissonRedLock redLock = new RedissonRedLock(locks);
    }

    /**
     * 直接使用工具类的方式测试验证
     */
    @Override
    public void redisLockTest() {
        int num = 3;
        //定义线程池
        ThreadFactory threadFactory = ThreadFactoryBuilder.create().setNameFormat("demo-redis-d").get();
        ThreadPoolExecutor pool = new ThreadPoolExecutor(0, 10, 1, TimeUnit.SECONDS, new SynchronousQueue<>(), threadFactory);

        /**
         * 第一种锁测试（获取不到立即返回）
         */
        String lockKey = "tryLock";
        StopWatch stopWatch = new StopWatch("第一种");
        CyclicBarrier barrier = new CyclicBarrier(num);
        stopWatch.start();
        //添加10个线程获取锁
        for (int i = 0; i < num; i++) {
            int temp = i;
            pool.submit(() -> {
                try {
                    System.out.println(barrier.await());
                } catch (InterruptedException | BrokenBarrierException e) {
                    log.error(e.getMessage());
                }
                boolean lock = false;
                try {
                    if (temp == 2) {
                        Thread.sleep(2000);
                    }
                    lock = redisLock.tryLock(lockKey);
                    //lock = redisLock.tryLock(lockKey, 1, TimeUnit.SECONDS);
                    log.info("tryLock：{} {}", temp, lock);
                    // 模拟业务
                    Thread.sleep(3000);
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    if (lock) {
                        redisLock.unlock(lockKey);
                        log.info("unlock：{} {}", temp, lockKey);
                    }
                }
            });
        }
        stopWatch.stop();
        stopWatch.start("wait");
        //当线程池中的线程数为0时，退出
        while (pool.getPoolSize() != 0) {
            try {
                Thread.sleep(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        System.out.println(stopWatch.getTotalTimeMillis());
        System.out.println();
        System.out.println();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        /**
         * 第二种锁测试（尝试获取锁 超时返回）
         */
        String tryLockKey = "tryLockWait";
        stopWatch = new StopWatch("第二种");
        barrier.reset();
        stopWatch.start();
        //添加10个线程获取锁
        for (int i = 0; i < num; i++) {
            int temp = i;
            pool.submit(() -> {
                try {
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                boolean lock = false;
                try {
                    lock = redisLock.tryLockWait(tryLockKey, 3, TimeUnit.SECONDS);
                    //lock = redisLock.tryLockWait(tryLockKey, 1, 3, TimeUnit.SECONDS);
                    log.info("tryLockWait：{} {}", temp, lock);
                    // 模拟业务
                    Thread.sleep(2000);
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    if (lock) {
                        redisLock.unlock(tryLockKey);
                        log.info("unlock：{} {}", temp, tryLockKey);
                    }

                }
            });
        }
        stopWatch.stop();
        //当线程池中的线程数为0时，退出
        stopWatch.start("wait");
        while (pool.getPoolSize() != 0) {
            try {
                Thread.sleep(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        System.out.println(stopWatch.getTotalTimeMillis());
        System.out.println();
        System.out.println();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        /**
         * 第三种锁测试（以阻塞方式的获取锁）
         */
        String lockBlock = "lockBlock";
        //添加10个线程获取锁
        stopWatch = new StopWatch("第三种");
        barrier.reset();
        stopWatch.start();
        for (int i = 0; i < num; i++) {
            int temp = i;
            pool.submit(() -> {
                try {
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                try {
                    redisLock.lock(lockBlock);
                    log.info("lockBlock：{} {}", temp, true);
                    // 模拟业务
                    Thread.sleep(1000);
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    redisLock.unlock(lockBlock);
                    log.info("unlock：{} {}", temp, lockBlock);
                }
            });
        }
        stopWatch.stop();
        //当线程池中的线程数为0时，退出
        stopWatch.start("wait");
        while (pool.getPoolSize() != 0) {
            try {
                Thread.sleep(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        System.out.println(stopWatch.getTotalTimeMillis());
    }

    /**
     * 使用注解的方式测试验证
     */
    @Override
    // 这个会报错因为代码没有执行完，就结束了
    // @DistributedLock(value = "AnnotationLock", expireTime = 1000, waitTime = 2000)
    @DistributedLock(value = "AnnotationLock", waitTime = 2000)
    public Object redisLockAnnotationTest() {
        StopWatch stopWatch = new StopWatch(Thread.currentThread().getId() + "");
        stopWatch.start();
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        System.out.println(stopWatch.getTotalTimeMillis());
        return Thread.currentThread().getId();
    }

    /**
     * 使用对象的某一个字段作为锁的key；
     */
    @Override
    @DistributedLock(value = "#model.name", waitTime = 2000)
    public Object redisLockAnnotationObjTest(RedisSerializableModel model) {
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return model;
    }

    /**
     * 使用对象的多个参数作为锁的key
     */
    @Override
    @DistributedLock(value = "'start' + #model.name + \"-zzzz-\" + #model.age + '-endfix'", waitTime = 2000)
    public Object redisLockAnnotationObjTestSpEL(RedisSerializableModel model) {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return model;
    }

}
